/**
 *  author: zhjpaul
 *  date:   2017-04-11
 */

var fs = require('fs'),
    path = require('path'),
    execSync = require('child_process').execSync,
    realTraceCDF = require('./CDF.json'),
    generateFlowDescriptionByCDF = require('./generateFlowByCDF').generateFlowDescription,  
    generateFlowDescriptionByRealTrace = require('./generateFlowByRealTrace').generateFlowDescription;  

var flowDescriptionContent = '',
    servers = [],
    topo, simus, cdfs, flows, flow;

// url: /simulation/start

/**
 * To generate topology file
 */

function generateTopoFile() {

    var topoLevel = topo.topoLevel,
        pHostNum = topo.pHostNum,
        hostNum = topo.hostNum,
        ctrlPos = topo.ctrlPos;

    if (topoLevel == 2) {

        var uSwitchNum = topo.uSwitchNum,
            lSwitchNum = topo.lSwitchNum,
            switchNum = uSwitchNum + lSwitchNum;
        
        console.log('[SIMULATION] While generate 2 level topology');
        var stdout = execSync('./a.out 2 ' + uSwitchNum + ' ' + pHostNum + ' ' + ctrlPos, {cwd: '../'});
        
    } else if (topoLevel == 3) {

        var coreSwitchNum = topo.coreSwitchNum,
            podNum = topo.podNum,
            pSwitchNum = topo.pSwitchNum;

        // TODO: to generate 3 layer topology file
    } else {
        console.log('[ERROR] Invalid topoLevel param');
    }
}

/**
 * To generate src and dst from a POD
 */

function getSrcDstFromPOD(pod) {
    var hostNum = topo.hostNum,
        addition = topo.podNum * topo.pSwitchNum,
        switchs = [],
        st, ed, i;

    st = hostNum + (pod-1)*topo.pSwitchNum;
    ed = hostNum + (pod)*topo.pSwitchNum;

    for (i = st; st < ed; i++) {
        switchs.push(i);
        switchs.push(i + addition);
    }

    flow.dst = flow.src = switchs[Math.floor(Math.random()*switchs.length)];
    while (flow.dst != flow.src) {
        flow.dst = switchs[Math.floor(Math.random()*switchs.length)];
    }
}


/*

   using python script.

function generateFlowDescriptionFileUsingRealTrace() {

    // convert from POD to src and dst
    if (flow.granularity == 'POD') {
        getSrcDstFromPOD(topo, flow.pod);
    }

    var params = [];
    params.push('default-flow.txt');
    params.push(simus.simuTime);
    params.push(flow.src);
    params.push(flow.dst);
    params.push(flow.proto);
    params.push(flow.num);

    if (flow.trace == '真实Trace数据') {
        params.push(0);
    }

    console.log('[INFO] While generate Description File');
    var stdout = execSync('python generator.py ' + params.join(' '), {
        cwd: path.resolve(__dirname, '../traces/');
    });
    console.log(stdout.toString('utf-8'));
}
*/

function updateServer(server) {
    
    for (var i = 0, len = server.length; i < len; i++) {
        if (servers.indexOf(server[i]) == -1) {
            servers.push(server[i]);
        }
    }
}

/**
 * To generate flow description file
 */ 

function generateFlowDescriptionFile() {

    var content,
        flowNum = 0;
    
    for (var i = 0, len = flows.length; i < len; i++) {

        flow = flows[i];
        flowNum += Number(flow.num);
        
        if (flow.trace == '真实Trace数据') {
            content = generateFlowDescriptionByRealTrace(parseInt(simus.simuTime), flow); 
            flowDescriptionContent += content.content;
            updateServer(content.server);
        } else if (flow.trace == '真实Trace流大小CDF分布') {
            console.log(flow.proto);
            content = generateFlowDescriptionByCDF(parseInt(simus.simuTime), flow, realTraceCDF[flow.proto]); 
            flowDescriptionContent += content.content;
            updateServer(content.server);
        } else {
            content = generateFlowDescriptionByCDF(parseInt(simus.simuTime), flow, cdfs[flow.trace]); 
            flowDescriptionContent += content.content;
            updateServer(content.server);
        }
    }

    for (var i = 0, len = servers.length; i < len; i++) {
        servers[i] = servers[i].split('-').join(' ');
    }

    flowDescriptionContent = [flowNum, flowDescriptionContent, servers.length, servers.join('\n')].join('\n');

    console.log('[SIMULATION] Full contents are\n', flowDescriptionContent);
    fs.writeFileSync(path.resolve(__dirname, '../default-flow.txt'), flowDescriptionContent);
}

/**
 * Start the simulation
 */

function start() {
    console.log('[INFO] While runing simulation');
    var stdout = execSync('./waf --run scratch/main > out.txt 2>&1', {
        cwd: path.resolve(__dirname, '../../')
    });
    console.log(stdout.toString('utf-8'));
}

function simulationStart(response, request, postData) {

    // Parse the params from User Input (in index.html)
    var data = JSON.parse(postData);
    simus = topo = data.simuParams;
    cdfs = data.CDFRules;
    flows = data.flows;
    
    // Step 1: to generate topology 
    generateTopoFile();

    // Step 2: to generate flow description files
    generateFlowDescriptionFile();

    // Step 3: start the simulation
    // start();
}

module.exports = simulationStart;
